﻿/**************************************************************
 *
 * 唯一标识：3a2173d2-fa2a-4cc4-b840-9d33e85c0a5a
 * 命名空间：Sgr.Generator.Segment
 * 创建时间：2024/6/20 11:10:53
 * 机器名称：DESKTOP-HJ4OAG9
 * 创建者：CocoYuan
 * 电子邮箱：fengqinhua2016@163.com
 * 描述：
 *
 * 经过权衡决定使用 object 作为同步锁对象，采用 Monitor 方案替换 ReaderWriterLockSlim。
 *
 **************************************************************/

using Sgr.Threading;

namespace Sgr.Generator.Segment
{
    public sealed class GenSegmentBuffer
    {
        /// <summary>
        /// 初始化状态枚举（互斥单维度）
        /// </summary>
        public enum BufferInitState
        {
            NotStarted = 0,
            InProgress = 1,
            Succeeded = 2,
            Failed = 3
        }

        private readonly string _key;                           //号段的标识
        private readonly GenSegment[] _segments;                //双Buffer

        private readonly object _sync = new();
        private readonly AtomicBoolean _threadRunning;          //线程是否在运行中
        private readonly AtomicLong _updateTimestamp;           //号段更新时间戳
        private readonly AtomicLong _errorCount;                //错误计数

        // 熔断重置时间（UTC Ticks，-1 表示未熔断）
        private long _circuitResetTimeTicks = -1;

        private int _currentPos;                // 当前段索引（写：Interlocked.Exchange；读：Volatile.Read）
        private int _nextReady;                 // 下一个段是否可切换（发布标志）
        private int _initState;                 // 初始化状态（枚举值存储为 int）
        private int _latestStep;                      // 步长

        public GenSegmentBuffer(string key)
        {
            _key = key ?? throw new ArgumentNullException(nameof(key));

            _segments = new GenSegment[2];
            _segments[0] = new GenSegment(this);
            _segments[1] = new GenSegment(this);

            _errorCount = new AtomicLong(0);
            _threadRunning = new AtomicBoolean(false);
            _updateTimestamp = new AtomicLong(0);
            _initState = (int)BufferInitState.NotStarted;
        }

        /// <summary>
        /// 标识
        /// </summary>
        public string Key => _key;

        /// <summary>
        /// 初始化状态
        /// </summary>
        public BufferInitState InitState => (BufferInitState)Volatile.Read(ref _initState);

        /// <summary>
        /// 是否已初始化完成
        /// </summary>
        public bool InitOk => InitState == BufferInitState.Succeeded;

        /// <summary>
        /// 尝试开始初始化（仅 NotStarted 或 Failed 可进入 InProgress）
        /// </summary>
        /// <returns></returns>
        public bool TryBeginInitialization()
        {
            while (true)
            {
                int cur = Volatile.Read(ref _initState);
                if (cur == (int)BufferInitState.InProgress || cur == (int)BufferInitState.Succeeded)
                    return false;
                if (cur != (int)BufferInitState.NotStarted && cur != (int)BufferInitState.Failed)
                    return false;

                // 进入进行中
                if (Interlocked.CompareExchange(ref _initState, (int)BufferInitState.InProgress, cur) == cur)
                    return true;
            }
        }

        /// <summary>
        /// 发布初始化成功（只有 InProgress 才能置成功）
        /// </summary>
        public void MarkInitializationSucceeded()
        {
            Interlocked.CompareExchange(ref _initState, (int)BufferInitState.Succeeded, (int)BufferInitState.InProgress);
        }

        /// <summary>
        /// 发布初始化失败（只有 InProgress 才能置失败）
        /// </summary>
        public void MarkInitializationFailed()
        {
            Interlocked.CompareExchange(ref _initState, (int)BufferInitState.Failed, (int)BufferInitState.InProgress);
        }

        /// <summary>
        /// 下一个 GenSegment 是否处于可切换状态
        /// </summary>
        public bool NextReady
        {
            get => Volatile.Read(ref _nextReady) == 1;
            set => Volatile.Write(ref _nextReady, value ? 1 : 0);
        }

        /// <summary>
        /// 最近一次使用的步长
        /// </summary>
        public int LatestStep
        {
            get => Volatile.Read(ref _latestStep);
            set => Volatile.Write(ref _latestStep, value);
        }

        /// <summary>
        /// 更新时间戳
        /// </summary>
        public long UpdateTimestamp
        {
            get => _updateTimestamp.Get();
            set => _updateTimestamp.Set(value);
        }

        /// <summary>
        /// 线程同步对象
        /// </summary>
        public object SyncRoot => _sync;

        /// <summary>
        /// 获取当前的使用的 GenSegment
        /// </summary>
        /// <returns></returns>
        public GenSegment GetCurrentGenSegment() => _segments[GetCurrentPos()];

        /// <summary>
        /// 获取下一个可切换的 GenSegment
        /// </summary>
        /// <returns></returns>
        public GenSegment GetNextGenSegment() => _segments[NextPos()];

        /// <summary>
        /// 获取当前段索引（0 或 1）
        /// </summary>
        public int GetCurrentPos() => Volatile.Read(ref _currentPos) & 1;

        /// <summary>
        /// 计算另一段索引（不修改状态）
        /// </summary>
        public int NextPos()
        {
            int cur = Volatile.Read(ref _currentPos);
            return (cur ^ 1) & 1;
        }

        /// <summary>
        /// 原子切换到另一段
        /// </summary>
        public void SwitchPos()
        {
            // 受调用方外层锁保护，无需 CAS 循环
            Interlocked.Exchange(ref _currentPos, (Volatile.Read(ref _currentPos) ^ 1) & 1);
        }

        //public void SwitchPos() => _currentPos ^= 1;    // 直接用异或操作切换状态

        #region 后台更新号段的线程运行状态

        /// <summary>
        /// 如果后台线程运行状态为未启动，则将其改为已启动状态 【线程安全】
        /// </summary>
        /// <returns>后台线程已启动则返回假</returns>
        public bool ChangeThreadStatuToRunning() => _threadRunning.CompareAndSet(false, true);

        /// <summary>
        /// 后台线程运行状态改为已停止状态 【线程安全】
        /// </summary>
        public void ChangeThreadStatuToStop() => _threadRunning.Set(false);

        /// <summary>
        /// 后台线程是否在运行中 【线程安全】
        /// </summary>
        /// <returns></returns>
        public bool IsThreadRunning() => _threadRunning.Get();

        #endregion 后台更新号段的线程运行状态

        #region 熔断相关

        /// <summary>
        /// 错误计数
        /// </summary>
        public long ErrorCount => _errorCount.Get();

        /// <summary>
        /// 增加错误计数并返回当前值
        /// </summary>
        /// <returns>增加后的错误计数</returns>
        public long IncrementErrorCount() => _errorCount.PreIncrement();

        /// <summary>
        /// 重置错误计数
        /// </summary>
        public void ResetErrorCount() => _errorCount.Set(0);

        /// <summary>
        /// 获取熔断重置时间
        /// </summary>
        public DateTime? CircuitResetTime
        {
            get
            {
                var ticks = Volatile.Read(ref _circuitResetTimeTicks);
                return ticks >= 0 ? new DateTime(ticks, DateTimeKind.Utc) : null;
            }
        }

        /// <summary>
        /// 检查键是否处于熔断状态
        /// </summary>
        /// <returns>如果处于熔断状态返回true，否则返回false</returns>
        public bool IsCircuitBreaking()
        {
            var ticks = Volatile.Read(ref _circuitResetTimeTicks);
            if (ticks < 0) return false;
            if (DateTime.UtcNow.Ticks > ticks)
            {
                // 尝试重置（无需强一致，仅做一次写）
                Volatile.Write(ref _circuitResetTimeTicks, -1);
                return false;
            }
            return true;
        }

        /// <summary>
        /// 触发熔断器
        /// </summary>
        /// <param name="resetSeconds">恢复时间(秒)</param>
        public void TripCircuit(int resetSeconds)
        {
            if (resetSeconds <= 0)
            {
                // 允许配置错误时立即自愈也无害，可选择抛异常或强制最小值
                resetSeconds = 1;
            }
            var target = DateTime.UtcNow.AddSeconds(resetSeconds).Ticks;
            Volatile.Write(ref _circuitResetTimeTicks, target);
        }

        #endregion 熔断相关
    }
}